package com.example.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.common.excel.ExcelUtils;
import com.example.domain.entity.LoginLog;
import com.example.domain.query.LoginLogQuery;
import com.example.mapper.LoginLogMapper;
import com.example.service.LoginLogService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class LoginLogServiceImpl implements LoginLogService {

    private final LoginLogMapper loginLogMapper;
    
    private static final Pattern BROWSER_PATTERN = Pattern.compile(
        "(MSIE|Firefox|Chrome|Safari|Opera)[/\\s]([\\d.]+)"
    );
    
    private static final Pattern OS_PATTERN = Pattern.compile(
        "(Windows NT|Mac OS X|Linux|Android|iOS)[\\s]?([\\d._]+)?"
    );

    @Override
    public void recordLoginLog(String username, String status, String message, HttpServletRequest request) {
        LoginLog loginLog = new LoginLog();
        String ip = getIpAddress(request);
        String userAgent = request.getHeader("User-Agent");
        
        loginLog.setUsername(username);
        loginLog.setStatus(status);
        loginLog.setMessage(message);
        loginLog.setIp(ip);
        loginLog.setCreateTime(LocalDateTime.now());
        loginLog.setLocation(getLocationByIp(ip));
        loginLog.setOs(parseOs(userAgent));
        loginLog.setBrowser(parseBrowser(userAgent));
        
        loginLogMapper.insert(loginLog);
    }

    @Override
    public void recordLoginLog(String username, String status, String message) {
        LoginLog loginLog = new LoginLog();
        loginLog.setUsername(username);
        loginLog.setStatus(status);
        loginLog.setMessage(message);
        loginLog.setCreateTime(LocalDateTime.now());
        
        loginLogMapper.insert(loginLog);
    }

    @Override
    public IPage<LoginLog> getLoginLogPage(LoginLogQuery query) {
        LambdaQueryWrapper<LoginLog> wrapper = new LambdaQueryWrapper<LoginLog>()
            .like(StringUtils.isNotBlank(query.getUsername()), LoginLog::getUsername, query.getUsername())
            .eq(StringUtils.isNotBlank(query.getStatus()), LoginLog::getStatus, query.getStatus())
            .ge(StringUtils.isNotBlank(query.getBeginTime()), LoginLog::getCreateTime, query.getBeginTime())
            .le(StringUtils.isNotBlank(query.getEndTime()), LoginLog::getCreateTime, query.getEndTime())
            .orderByDesc(LoginLog::getCreateTime);

        return loginLogMapper.selectPage(
            new Page<>(query.getPageNum(), query.getPageSize()),
            wrapper
        );
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteLoginLogByIds(List<Long> ids) {
        if (ids != null && !ids.isEmpty()) {
            loginLogMapper.deleteBatchIds(ids);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clearLoginLog() {
        // 先查询所有未删除的记录ID
        LambdaQueryWrapper<LoginLog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LoginLog::getDeleted, 0)
                   .select(LoginLog::getId);
        List<LoginLog> logs = loginLogMapper.selectList(queryWrapper);
        
        if (!logs.isEmpty()) {
            List<Long> ids = logs.stream()
                               .map(LoginLog::getId)
                               .collect(Collectors.toList());
            // 使用批量删除
            loginLogMapper.deleteBatchIds(ids);
        }
    }

    @Override
    public void exportLoginLog(LoginLogQuery query, HttpServletResponse response) {
        LambdaQueryWrapper<LoginLog> wrapper = new LambdaQueryWrapper<LoginLog>()
            .like(StringUtils.isNotBlank(query.getUsername()), LoginLog::getUsername, query.getUsername())
            .eq(StringUtils.isNotBlank(query.getStatus()), LoginLog::getStatus, query.getStatus())
            .ge(StringUtils.isNotBlank(query.getBeginTime()), LoginLog::getCreateTime, query.getBeginTime())
            .le(StringUtils.isNotBlank(query.getEndTime()), LoginLog::getCreateTime, query.getEndTime())
            .orderByDesc(LoginLog::getCreateTime);

        List<LoginLog> list = loginLogMapper.selectList(wrapper);
        
        ExcelUtils.export(response, "登录日志", LoginLog.class, list);
    }

    private String getIpAddress(HttpServletRequest request) {
        String[] headers = {
            "X-Forwarded-For",
            "Proxy-Client-IP",
            "WL-Proxy-Client-IP",
            "HTTP_CLIENT_IP",
            "HTTP_X_FORWARDED_FOR",
            "X-Real-IP"
        };
        
        String ip = null;
        for (String header : headers) {
            ip = request.getHeader(header);
            if (isValidIp(ip)) {
                break;
            }
        }
        
        if (!isValidIp(ip)) {
            ip = request.getRemoteAddr();
        }
        
        // 多个IP时取第一个
        if (isValidIp(ip) && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }
        
        return ip == null ? "unknown" : ip;
    }

    private boolean isValidIp(String ip) {
        return ip != null && ip.length() > 0 && !"unknown".equalsIgnoreCase(ip);
    }

    private String parseBrowser(String userAgent) {
        if (userAgent == null) {
            return "未知浏览器";
        }
        
        // 移动端浏览器特殊处理
        if (userAgent.contains("MicroMessenger")) {
            return "微信浏览器";
        } else if (userAgent.contains("QQBrowser")) {
            return "QQ浏览器";
        } else if (userAgent.contains("UCBrowser")) {
            return "UC浏览器";
        }
        
        // 常规浏览器
        Matcher matcher = BROWSER_PATTERN.matcher(userAgent);
        if (matcher.find()) {
            String browser = matcher.group(1);
            String version = matcher.group(2);
            return browser + " " + version;
        }
        
        return "其他浏览器";
    }

    private String parseOs(String userAgent) {
        if (userAgent == null) {
            return "未知系统";
        }
        
        // 移动端系统特殊处理
        if (userAgent.contains("iPhone") || userAgent.contains("iPad")) {
            return "iOS";
        } else if (userAgent.contains("Android")) {
            return "Android";
        }
        
        // 常规操作系统
        Matcher matcher = OS_PATTERN.matcher(userAgent);
        if (matcher.find()) {
            String os = matcher.group(1);
            String version = matcher.group(2);
            
            // 美化显示
            switch (os) {
                case "Windows NT":
                    return parseWindowsVersion(version);
                case "Mac OS X":
                    return "macOS " + (version != null ? version.replace("_", ".") : "");
                default:
                    return os + (version != null ? " " + version : "");
            }
        }
        
        return "其他系统";
    }

    private String parseWindowsVersion(String version) {
        if (version == null) return "Windows";

        return switch (version) {
            case "10.0" -> "Windows 10";
            case "6.3" -> "Windows 8.1";
            case "6.2" -> "Windows 8";
            case "6.1" -> "Windows 7";
            case "6.0" -> "Windows Vista";
            case "5.2" -> "Windows Server 2003";
            case "5.1" -> "Windows XP";
            default -> "Windows " + version;
        };
    }

    private String getLocationByIp(String ip) {
        // TODO: 实现IP地址解析
        return "未知地区";
    }
}